package spitfire.ksim.node;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import spitfire.ksim.data.KSensorSnapshot;
import TJavaLib.TList;

/**
 * <p>The KSensor class represents a single sensor. 
 * A sensor has a type information, and can provide a series of sensed data with 
 * corresponding time stamp. It may also have an optional semantic description.</p>
 * 
 * <p>The data is populated when loading from sensor node profile.</p>
 * 
 * @author Adam
 *
 */
public class KSensor {
	private static final double THRESHOLD_COE = 0.8;
	private static final int MOVING_AVERAGE_WINDOW = 5; //
	private TList rawLen = new TList();
	private int averageLen = 0;
	
	private String sensorType;
	private String description; 
	private List<Long> timeStampList = new ArrayList<Long>();
	private List<Double> dataList = new ArrayList<Double>();
	
	public KSensor() {}
	
	public KSensor(String sensorType) {
		this.sensorType = sensorType;
	}
	
	public void setSensorType(String sensorType) {
		this.sensorType = sensorType;
	}

	public String getSensorType() {
		return sensorType;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getDescription() {
		return description;
	}

	public void addTimeAndData(Long timeStamp, Double value) {
		getTimeStampList().add(timeStamp);
		getDataList().add(value);
	}
	
	public KSensorSnapshot takeSnapshot(long fromTime, long toTime) {
//		int fromIndex = Collections.binarySearch(getTimeStampList(), fromTime);
//		int toIndex = Collections.binarySearch(getTimeStampList(), toTime);
//		if (fromIndex < 0) {
//			// not found, convert to insertion point. @see Collections.binarySearch; 
//			fromIndex = -fromIndex - 1;
//		}
//		if (toIndex < 0) {
//			toIndex = -toIndex - 1;
//		}
//		List<Long> timeSnapshot = new ArrayList<Long>(getTimeStampList().subList(fromIndex, toIndex));
//		List<Double> valueSnapshot = new ArrayList<Double>(getDataList().subList(fromIndex, toIndex));
//		return new KSensorSnapshot(timeSnapshot, valueSnapshot);
		int d = 100;
		long interval = (toTime - fromTime) / d;
		List<Long> timeSnapshot = new ArrayList<Long>();
		List<Double> valueSnapshot = new ArrayList<Double>();
		for (int dCount = 0; dCount < d; dCount++) {
			long dFrom = fromTime + dCount * interval;
			long dTo = fromTime + (dCount + 1) * interval;
			int fromIndex = Collections.binarySearch(getTimeStampList(), dFrom);
			int toIndex = Collections.binarySearch(getTimeStampList(), dTo);
			if (fromIndex < 0) {
				// not found, convert to insertion point. @see Collections.binarySearch; 
				fromIndex = -fromIndex - 1;
			}
			if (toIndex < 0) {
				toIndex = -toIndex - 1;
			}
			Double avg = null;
			if (fromIndex != toIndex) {
				avg = avg(getDataList().subList(fromIndex, toIndex));
			}
			timeSnapshot.add(dFrom + interval / 2);
			valueSnapshot.add(avg);
		}
		return new KSensorSnapshot(timeSnapshot, valueSnapshot);
		
	}
	
	private double avg(List<Double> list) {
		double sum = 0;
		for (Double value: list) {
			sum += value;
		}
		return sum / list.size();
	}

	//judge whether the raw data is sufficient, here 80% 
	public boolean isSufficient(KSensorSnapshot sensorSnapshot){
//		boolean flag = true;
//		int size = sensorSnapshot.getTimeStampList().size();
//		if (size == 0) {
//			return false;
//		}
//		long timeMin = sensorSnapshot.getTimeStampList().get(0);
//		long timeMax = sensorSnapshot.getTimeStampList().get(size - 1);
//
//		// System.err.println("type="+type+"averageLen*0.8="+(averageLen*0.8)+"data.len="+sData.len());
//		if ((timeMax * 1.0 - timeMin) < KSensorNode.DEFAULT_SNAPSHOT_LEN * THRESHOLD_COE
//				|| size < averageLen * THRESHOLD_COE) {
//			flag = false;
//		}
//		if (rawLen.len() == 0) {
//			rawLen.enQueue(size);
//			averageLen = size;
//		} else if (rawLen.len() < MOVING_AVERAGE_WINDOW) {
//			rawLen.enQueue(size);
//			averageLen = (averageLen * (rawLen.len() - 1) + size)
//					/ rawLen.len();
//		} else if (rawLen.len() >= MOVING_AVERAGE_WINDOW) {
//			int M = (Integer) rawLen.deQueue();
//			rawLen.enQueue(size);
//			averageLen = averageLen - M / MOVING_AVERAGE_WINDOW + size
//					/ MOVING_AVERAGE_WINDOW;
//		}
//		// System.err.println("type="+type+"falg="+flag);
//		return flag;
		List<Double> list = sensorSnapshot.getDataList();
		int count = 0;
		for (Double d : list) {
			if (d == null) {
				count++;
			}
		}
		if (count * 1.0 / list.size() > 0.2) {
			return false;
		} else {
			return true;
		}
	}

	public List<Long> getTimeStampList() {
		return timeStampList;
	}
	
	public List<Double> getDataList() {
		return dataList;
	}
}
